////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2010.
// -------------------------------------------------------------------------
//  Version:     v1.00
//  Created:     Michael Kopietz
//  Description: unified vector math lib
// -------------------------------------------------------------------------
//  History:		- created 1999  for Katmai and K3
//							-	...
//							-	integrated into cryengine
//
////////////////////////////////////////////////////////////////////////////
#ifndef __D_VMATH_C__
#define __D_VMATH_C__


union vec4
{
	struct
	{
		float m_Xf;
		float m_Yf;
		float m_Zf;
		float m_Wf;
	};
	struct
	{
		uint32 m_Xu;
		uint32 m_Yu;
		uint32 m_Zu;
		uint32 m_Wu;
	};
	struct
	{
		int32 m_Xs;
		int32 m_Ys;
		int32 m_Zs;
		int32 m_Ws;
	};
	float m_f[4];
	int32 m_s[4];
	uint32 m_u[4];
};

#include "VMath_Prototypes.hpp"

#define SWIZZLEMASK5(X,Y,Z,W)	((X)|(Y<<2)|(Z<<4)|(W<<6))
#define SWIZZLEMASK4(N,X,Y,Z)	N##x	=	SWIZZLEMASK5(X,Y,Z,0),\
								N##y	=	SWIZZLEMASK5(X,Y,Z,1),\
								N##z	=	SWIZZLEMASK5(X,Y,Z,2),\
								N##w	=	SWIZZLEMASK5(X,Y,Z,3),
#define SWIZZLEMASK3(N,X,Y)		SWIZZLEMASK4(N##x,X,Y,0)\
								SWIZZLEMASK4(N##y,X,Y,1)\
								SWIZZLEMASK4(N##z,X,Y,2)\
								SWIZZLEMASK4(N##w,X,Y,3)
#define SWIZZLEMASK2(N,X)		SWIZZLEMASK3(N##x,X,0)\
								SWIZZLEMASK3(N##y,X,1)\
								SWIZZLEMASK3(N##z,X,2)\
								SWIZZLEMASK3(N##w,X,3)
#define SWIZZLEMASK1			SWIZZLEMASK2(x,0)\
								SWIZZLEMASK2(y,1)\
								SWIZZLEMASK2(z,2)\
								SWIZZLEMASK2(w,3)

enum ESwizzleMask
{
	SWIZZLEMASK1
};
enum ECacheLvl
{
	ECL_LVL1,
	ECL_LVL2,
	ECL_LVL3,
};
#define BitX	1
#define BitY	2
#define BitZ	4
#define BitW	8

	ILINE vec4				Vec4(float x,float y,float z,float w)
								{
									vec4 Ret;
									Ret.m_Xf	=	x;
									Ret.m_Yf	=	y;
									Ret.m_Zf	=	z;
									Ret.m_Wf	=	w;
									return Ret;
								}
	ILINE vec4				Vec4(uint32 x,uint32 y,uint32 z,uint32 w)
								{
									vec4 Ret;
									Ret.m_Xu	=	x;
									Ret.m_Yu	=	y;
									Ret.m_Zu	=	z;
									Ret.m_Wu	=	w;
									return Ret;
								}
	ILINE vec4				Vec4(float x)
								{
									return Vec4(x,x,x,x);
								}
	ILINE int32				Vec4int32(vec4 V,uint32 Idx)
								{
									return V.m_s[Idx];
								}
	ILINE vec4				Vec4Zero()
								{
									return Vec4(0.f);
								}

	ILINE vec4				Vec4One()
								{
									return Vec4(1.f,1.f,1.f,1.f);
								}
	ILINE vec4				Vec4Four()
								{
									return Vec4(4.f,4.f,4.f,4.f);
								}
	ILINE vec4				Vec4ZeroOneTwoThree()
								{
									return Vec4(0.f,1.f,2.f,3.f);
								}
	ILINE vec4				Vec4FFFFFFFF()
								{
									return Vec4(~0u,~0u,~0u,~0u);
								}
	ILINE vec4				Vec4Epsilon()
								{
									return Vec4(FLT_EPSILON);
								}
	template<ECacheLvl L>
	ILINE void				Prefetch(const void* pData)
								{
								}
	template<ESwizzleMask M>
	ILINE vec4				Shuffle(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_u[M&3],V0.m_u[(M>>2)&3],V1.m_u[(M>>4)&3],V1.m_u[(M>>6)&3]);
								}
	template<ESwizzleMask M>
	ILINE vec4				Swizzle(vec4 V)
								{
									return Shuffle<M>(V,V);
								}
	ILINE vec4				Add(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_Xf+V1.m_Xf,
												V0.m_Yf+V1.m_Yf,
												V0.m_Zf+V1.m_Zf,
												V0.m_Wf+V1.m_Wf);
								}
	ILINE vec4				Sub(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_Xf-V1.m_Xf,
												V0.m_Yf-V1.m_Yf,
												V0.m_Zf-V1.m_Zf,
												V0.m_Wf-V1.m_Wf);
								}
	ILINE vec4				Mul(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_Xf*V1.m_Xf,
												V0.m_Yf*V1.m_Yf,
												V0.m_Zf*V1.m_Zf,
												V0.m_Wf*V1.m_Wf);
								}
	ILINE vec4				Div(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_Xf/V1.m_Xf,
												V0.m_Yf/V1.m_Yf,
												V0.m_Zf/V1.m_Zf,
												V0.m_Wf/V1.m_Wf);
								}
	ILINE vec4				RcpFAST(vec4 V)
								{
									return Div(Vec4One(),V);
								}
	ILINE vec4				DivFAST(vec4 V0,vec4 V1)
								{
									return Div(V0,V1);
								}
	ILINE vec4				Rcp(vec4 V)
								{
									return Div(Vec4One(),V);
								}
	ILINE vec4				Madd(vec4 V0,vec4 V1,vec4 V2)
								{
									return Add(V2,Mul(V0,V1));
								}
	ILINE vec4				Msub(vec4 V0,vec4 V1,vec4 V2)
								{
									return Sub(Mul(V0,V1),V2);
								}
	ILINE vec4				Min(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_Xf<V1.m_Xf?V0.m_Xf:V1.m_Xf,
												V0.m_Yf<V1.m_Yf?V0.m_Yf:V1.m_Yf,
												V0.m_Zf<V1.m_Zf?V0.m_Zf:V1.m_Zf,
												V0.m_Wf<V1.m_Wf?V0.m_Wf:V1.m_Wf);
								}
	ILINE vec4				Max(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_Xf>V1.m_Xf?V0.m_Xf:V1.m_Xf,
												V0.m_Yf>V1.m_Yf?V0.m_Yf:V1.m_Yf,
												V0.m_Zf>V1.m_Zf?V0.m_Zf:V1.m_Zf,
												V0.m_Wf>V1.m_Wf?V0.m_Wf:V1.m_Wf);
								}
	ILINE vec4				floatToint32(vec4 V)
								{
									return Vec4(static_cast<uint32>(static_cast<int32>(V.m_Xf)),
												static_cast<uint32>(static_cast<int32>(V.m_Yf)),
												static_cast<uint32>(static_cast<int32>(V.m_Zf)),
												static_cast<uint32>(static_cast<int32>(V.m_Wf)));
								}
	ILINE vec4				int32Tofloat(vec4 V)
								{
									return Vec4(static_cast<float>(V.m_Xs),
												static_cast<float>(V.m_Ys),
												static_cast<float>(V.m_Zs),
												static_cast<float>(V.m_Ws));
								}
	ILINE vec4				CmpLE(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_Xf<=V1.m_Xf?~0u:0u,
												V0.m_Yf<=V1.m_Yf?~0u:0u,
												V0.m_Zf<=V1.m_Zf?~0u:0u,
												V0.m_Wf<=V1.m_Wf?~0u:0u);
								}
	ILINE uint32				SignMask(vec4 V)
								{
									return (V.m_Xu>>31)|((V.m_Yu>>31)<<1)|((V.m_Zu>>31)<<2)|((V.m_Wu>>31)<<3);
								}
	ILINE vec4				And(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_Xu&V1.m_Xu,
												V0.m_Yu&V1.m_Yu,
												V0.m_Zu&V1.m_Zu,
												V0.m_Wu&V1.m_Wu);
								}
	ILINE vec4				AndNot(vec4 V0,vec4 V1)
								{
									return Vec4((~V0.m_Xu)&V1.m_Xu,
												(~V0.m_Yu)&V1.m_Yu,
												(~V0.m_Zu)&V1.m_Zu,
												(~V0.m_Wu)&V1.m_Wu);
								}
	ILINE vec4				Or(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_Xu|V1.m_Xu,
												V0.m_Yu|V1.m_Yu,
												V0.m_Zu|V1.m_Zu,
												V0.m_Wu|V1.m_Wu);
								}
	ILINE vec4				Xor(vec4 V0,vec4 V1)
								{
									return Vec4(V0.m_Xu^V1.m_Xu,
												V0.m_Yu^V1.m_Yu,
												V0.m_Zu^V1.m_Zu,
												V0.m_Wu^V1.m_Wu);
								}
	ILINE vec4				Select(vec4 V0,vec4 V1,vec4 M)
								{
									return SelectSign(V0,V1,M);
								}
	ILINE vec4				ShiftAR(vec4 V,uint32 Count)
								{
									return Vec4(static_cast<uint32>(V.m_Xs>>Count),
												static_cast<uint32>(V.m_Ys>>Count),
												static_cast<uint32>(V.m_Zs>>Count),
												static_cast<uint32>(V.m_Ws>>Count));
								}
	ILINE vec4				SelectSign(vec4 V0,vec4 V1,vec4 M)
								{
									M	=	ShiftAR(M,31);
									return Or(AndNot(M,V0),And(M,V1));
								}


#endif

